package com.maiyuren.fishkit.ui.components.dict

import android.annotation.SuppressLint
import android.os.Build
import android.view.ViewGroup
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.RequiresApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.absoluteOffset
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.KeyboardArrowDown
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.zIndex
import com.maiyuren.fishkit.dict.FishDict
import com.maiyuren.fishkit.dict.FishDictGroup
import com.maiyuren.fishkit.history.HistoryManager
import com.maiyuren.fishkit.ui.components.FishTabDelegate
import com.maiyuren.fishkit.ui.pages.main.titleBarHeight
import com.maiyuren.fishkit.utils.FishEvent
import com.maiyuren.fishkit.utils.FishEventBus
import com.maiyuren.fishkit.utils.logD
import com.maiyuren.fishkit.utils.toDp
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.util.concurrent.locks.ReentrantLock

data class TabItem(
    val title: String,
    val dict: FishDict,
    var webView: WebView? = null,
    var lastSearchWord: String = "",
    var lastSearchIsReg: Boolean = false,
    var lastSearchIsForce: Boolean = false,
    val locker: ReentrantLock  = ReentrantLock()
)

@OptIn(ExperimentalMaterial3Api::class)
class DictTabDelegate(val group: MutableState<FishDictGroup?>, val onMenuChange: (Int)->Unit) : FishTabDelegate {
    val tabs: MutableList<TabItem> by lazy {
        val dicts = group.value?.items;
        if (dicts == null) {
            mutableListOf()
        }
        else {
            val v: MutableList<TabItem> = mutableListOf()
            for(i in 0 until dicts.size) {
                val dict = dicts[i]
                v.add(TabItem(title = dicts[i].name, dict = dict))
            }

            v
        }
    }

//    val currDictTitle = mutableStateOf(tabs[tabIndex.value!!].title)

    fun search(index: Int, word: String, isReg: Boolean = false, force:Boolean = false) {
        val tab = tabs[index]
        if (!force && tab.lastSearchWord == word) return

        val r = tab.dict.lookfor(wordOrReg = word, isReg = isReg)
        tab.lastSearchIsReg = isReg
        tab.lastSearchIsForce = force
        if (tab.dict.isWeb()) {
            if (tab.webView != null) {
                r.words[0].content?.let { tab.webView?.loadUrl(it) }
                tab.lastSearchWord = word
            }
        } else {
            var c: String? = ""
            if (r.errorMsg != null) {
                c = r.errorMsg
            } else {
                c = tab.dict.loadWordContent(r.words[0], r.redirectResult)
                tab.lastSearchWord = word
            }
            c?.let {
                val temp = handle_dict_lookfor_result(it)
                tab.webView?.loadDataWithBaseURL("./", temp, "text/html", "utf-8", null)
            }
        }

        if (r.errorMsg == null && r.words.size > 0) {
            if (force) {
                HistoryManager.instance().addWord(r.words[0].word)
            }
            FishEventBus.emit(FishEvent.searchResult, r.words[0].word)
        } else {
            FishEventBus.emit(FishEvent.searchResult, null)
        }
    }

    override fun onCount(): Int {
        return tabs.size
    }

    override fun onTabTitle(i: Int): String {
        return tabs[i].title
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    @Composable
    override fun onTabContentView(i: Int) {
        Column(modifier = Modifier
            .fillMaxSize()) {
            Column(
                modifier = Modifier
                    .height(titleBarHeight)
                    .zIndex(1F)
                    .background(MaterialTheme.colorScheme.background),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                DictMenuButton(tabIndex = i)
            }

            AndroidView(modifier = Modifier
                .weight(1F), factory = {
                if (tabs[i].webView != null) tabs[i].webView!!
                else {
                    tabs[i].webView = WebView(it).apply {
                        layoutParams = ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT
                        )
                        settings.javaScriptEnabled = true;
                        settings.allowFileAccess = true;
                        settings.allowFileAccessFromFileURLs = true;
                        settings.allowContentAccess = true;
                        settings.allowUniversalAccessFromFileURLs = true;
                        settings.domStorageEnabled = true;
                        settings.defaultTextEncodingName = "UTF-8"
                        settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
                        settings.blockNetworkImage = false

                        webViewClient = object : WebViewClient() {
                            override fun shouldOverrideUrlLoading(
                                view: WebView,
                                request: WebResourceRequest
                            ): Boolean {
                                val scheme = request.url.scheme?.lowercase();
                                if (scheme != null) {
                                    if (scheme.equals("http") || scheme.equals("https")) {
                                        return false
                                    }

                                    if (scheme.equals("fishdict")) {
                                        if (request.url.toString().startsWith("fishdict://go?")) {
                                            FishEventBus.emit(FishEvent.goWord, request.url.getQueryParameter("word"))
                                        }
                                    }
                                }
                                return true
                            }

                            @SuppressLint("ResourceType")
                            override fun shouldInterceptRequest(
                                view: WebView?,
                                request: WebResourceRequest?
                            ): WebResourceResponse? {
                                val url = request?.url.toString()
                                url.logD()
                                if (url.startsWith("http://fishdict/assets/")) {
                                    val header = "http://fishdict/"
                                    var buf: ByteArray? = null
                                    tabs[i].locker.lock();
                                    buf = tabs[i].dict.readFileBytes(request!!.url.toString().substring(header.length))
                                    tabs[i].locker.unlock();
                                    if (buf != null) {
                                        val stream: InputStream = ByteArrayInputStream(buf)
                                        return WebResourceResponse(
                                            "application/octet-stream",
                                            "UTF-8",
                                            stream
                                        )
                                    }
                                }
//                                else if (url == "http://fishdict/font/dict.ttf") {
//                                    val stream: InputStream? = FishkitApplication.instance.assets.open("fonts/dict.ttf")
//                                        // FishResourceFileUtils.open(R.font.dict)
//                                    val ct = request!!.requestHeaders["Content-Type"];
//                                    return WebResourceResponse(
//                                        "application/x-font-ttf",
//                                        "UTF8",
//                                        stream
//                                    )
//                                }
                                return super.shouldInterceptRequest(view, request)
                            }
                        }
                    }
                    if (tabs[i].lastSearchWord != null) {
                        val temp = tabs[i].lastSearchWord
                        tabs[i].lastSearchWord = ""
                        search(index = i, word = temp, isReg = tabs[i].lastSearchIsReg, force = tabs[i].lastSearchIsForce)
                    }

                    tabs[i].webView!!
                }
            })
        }
    }


    @Composable
    private fun DictMenuButton(modifier: Modifier = Modifier, tabIndex: Int) {
        var showDictMenu by remember {
            mutableStateOf(false)
        }

        var containerPosition by remember {
            mutableStateOf(Rect.Zero)
        }

        var menuPosition by remember {
            mutableStateOf(Rect.Zero)
        }

        Box(modifier = modifier
            .padding(PaddingValues(horizontal = 8.dp, vertical = 2.dp))
            .height(48.dp)
            .fillMaxWidth()
            .clickable {
                showDictMenu = !showDictMenu
            }
            .onGloballyPositioned {
                containerPosition = it.boundsInWindow()
            },
            contentAlignment = Alignment.BottomCenter
        ) {
            Icon(
                modifier = Modifier
                    .size(20.dp)
                    .padding(0.dp),
                imageVector = Icons.Outlined.KeyboardArrowDown,
                contentDescription = null,
                tint = Color(0x88000000)
            )

            Text(
                modifier = Modifier.absoluteOffset(y = -14.dp),
                text = tabs[tabIndex].title,
                color = MaterialTheme.colorScheme.onPrimary)

            DropdownMenu(
                modifier = Modifier
                    .background(MaterialTheme.colorScheme.background)
                    .onGloballyPositioned {
                        menuPosition = it.boundsInWindow()
                    },
                offset = DpOffset(x = (containerPosition.left + (containerPosition.width - menuPosition.width) / 2F).toDp() - 8.dp, y= 4.dp),
                expanded = showDictMenu,
                onDismissRequest = { showDictMenu = false }
            ) {
                tabs.forEachIndexed { index, value->
                    DropdownMenuItem(
                        modifier = Modifier.height(30.dp),
                        text = @Composable {
                            Text(
                                modifier = Modifier.padding(0.dp),
                                text = value.title,
                                color = MaterialTheme.colorScheme.onPrimary,
                            )
                        },
                        onClick = {
                            showDictMenu = false;
                            if (index != tabIndex) {
                                onMenuChange(index)
                            }
                        })
                }
            }
        }
    }
}